﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using Might.GraphicsEditor.GraphicsObjects;
using Might.GraphicsEditor.Presenter;

namespace Might.GraphicsEditor.Tools {
    /// <summary>
    /// Class used for selecting ojects on canvas
    /// </summary>
    internal class Rubberband : ITool {
        // TODO resize "this" instead of r
        private readonly Rectangle r;
        private GraphicsComponent MovingItem;

        /// <summary>
        /// Constructor for Rubberband class
        /// </summary>
        /// <param name="gl">Main Drawing canvas</param>
        internal Rubberband(IconPresenter gl) {
            graphics = gl;

            r = new Rectangle {
                Stroke = new SolidColorBrush(Colors.White),
                StrokeDashArray = new DoubleCollection {3, 4},
                StrokeDashOffset = 1
            };

            Content = r;
            Visibility = Visibility.Collapsed;
        }

        /// <summary>
        /// Througput function for receiving mouse down events from canvas.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal override void GetMouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
            startPoint = endPoint = e.GetPosition(graphics.canvas);

            GeneralTransform gt = graphics.canvas.TransformToVisual(Application.Current.RootVisual);
            Point pnt = gt.Transform(startPoint);
            GraphicsComponent obj = VisualTreeHelper.FindElementsInHostCoordinates(pnt, graphics.canvas)
                .OfType<GraphicsComponent>()
                .FirstOrDefault();

            // if there's any
            if (obj != null) {
                if (Keyboard.Modifiers == ModifierKeys.Shift) {
                    if (graphics.IsSelected(obj)) {
                        graphics.RemoveShape(obj);
                    } else {
                        graphics.AddShape(obj);
                    }
                } else {
                    MovingItem = obj;
                    if (graphics.IsSelected(obj)) {
                        // switch Draw/Scale - Rotate/Scew
                    } else {
                        graphics.SetShape(obj);
                    }

                    obj.CaptureMouse();
                    IsMouseCaptured = true;
                }
                e.Handled = true;
                return;
            }

            // no shape is under current click, so create rubberband
            r.CaptureMouse();
            IsMouseCaptured = true;

            if (Keyboard.Modifiers != ModifierKeys.Shift) {
                graphics.ClearSelection();
            }

            r.Width = r.Height = 0;
            Visibility = Visibility.Visible;

            e.Handled = true;
        }

        /// <summary>
        /// Througput function for receiving mouse move events from canvas.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal override void GetMouseMove(object sender, MouseEventArgs e) {
            if (IsMouseCaptured) {
                endPoint = e.GetPosition(graphics.canvas);
                //if (endPoint.X < 0 || endPoint.X > graphics.canvas.ActualWidth ||
                //    endPoint.Y < 0 || endPoint.Y > graphics.canvas.ActualHeight) {
                //    return;
                //}

                if (MovingItem != null) {
                    MoveSelection(e);
                } else {
                    r.Width = Math.Abs(startPoint.X - endPoint.X);
                    r.Height = Math.Abs(startPoint.Y - endPoint.Y);
                    Canvas.SetLeft(this, Math.Min(startPoint.X, endPoint.X));
                    Canvas.SetTop(this, Math.Min(startPoint.Y, endPoint.Y));
                }
            }
        }

        /// <summary>
        /// Througput function for receiving mouse up events from canvas.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal override void GetMouseLeftButtonUp(object sender, MouseButtonEventArgs e) {
            if (IsMouseCaptured) {
                if (MovingItem != null) {
                    MovingItem.ReleaseMouseCapture();
                    IsMouseCaptured = false;
                    MovingItem = null;
                    graphics.MoveSelection();

                    e.Handled = true;
                    return;
                }
                GeneralTransform gt = graphics.canvas.TransformToVisual(Application.Current.RootVisual);
                Point pntStart = gt.Transform(startPoint);
                Point pntEnd = gt.Transform(endPoint);
                List<GraphicsComponent> list =
                    VisualTreeHelper.FindElementsInHostCoordinates(new Rect(pntStart, pntEnd), graphics.canvas)
                        .OfType<GraphicsComponent>()
                        .ToList();

                if (Keyboard.Modifiers == ModifierKeys.Shift) {
                    graphics.AddSelection(list);
                } else {
                    graphics.SetSelection(list);
                }

                // remove adorner (=this) from adorner layer
                Visibility = Visibility.Collapsed;

                r.ReleaseMouseCapture();
                IsMouseCaptured = false;
            }

            e.Handled = true;
        }

        private void MoveSelection(MouseEventArgs e) {
            Point point = e.GetPosition(graphics.canvas);

            var delta = new Point(point.X - startPoint.X, point.Y - startPoint.Y);
            graphics.PreviewMoveSelection(delta);

            startPoint = point;
        }
    }
}
